using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Shell;
using RapidDownloader.Model;
using RapidDownloader.Model.Helpers;
using RapidDownloader.Modules.DownloadModule;
using RapidDownloader.Modules.DownloadQueueModule;
using Vidyano;
using Vidyano.Services;

namespace RapidDownloader
{
    partial class Application
    {
        #region Fields

        private readonly TaskbarItemInfo info = new TaskbarItemInfo();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern ExecutionState SetThreadExecutionState(ExecutionState esFlags);

        #endregion

        protected override void OnServicesLoaded()
        {
            base.OnServicesLoaded();

            // Initialize/Override Services
            ServiceLocator.RegisterService(typeof(IAuthenticatorService), new RapidShareAuthenticatorService());

            // Update Progress Bar
            MessageBus.Listen<FileDownloadProgressMessage>().ObserveOnDispatcher().Subscribe(_ => UpdateTaskBar(DownloadQueueModule.Current.QueuedDownloads.ToArray()));
            MessageBus.Listen<FileWriteProgressMessage<DownloadFile>>().Where(fwp => fwp.IsCompleted).ObserveOnDispatcher().Subscribe(_ => UpdateTaskBar(DownloadQueueModule.Current.QueuedDownloads.ToArray()));
            MessageBus.Listen<DownloadModule[]>().ObserveOnDispatcher().Subscribe(UpdateTaskBar);
        }

        protected override Vidyano.Windows.ShellWindow CreateShellWindow()
        {
            var result = base.CreateShellWindow();
            result.TaskbarItemInfo = info;
            return result;
        }

        #region Private Methods

        private void UpdateTaskBar(DownloadModule[] queuedDownloads)
        {
            var count = queuedDownloads.Length;

            info.Description = count > 0 ? string.Format("Files: {0}/{1}\r\nSpeed: {2}", CountFiles(queuedDownloads, _ => true), CountFiles(queuedDownloads, df => df.DownloadState == TaskProgressState.Complete), DownloadQueueModule.Current.BandwidthUsage.FormatSize("/s")) : string.Empty;

            if (count == 0 || queuedDownloads.All(dm => dm.DownloadProgress >= 100d))
                info.ProgressState = TaskbarItemProgressState.None;
            else if (!HasFailedDownload(queuedDownloads))
            {
                info.ProgressState = TaskbarItemProgressState.Normal;
                var value = Math.Round((queuedDownloads.Sum(dm => dm.DownloadProgress) / count) / 100d, 2);
                if (info.ProgressValue != value)
                {
                    info.ProgressValue = value;
                    SetThreadExecutionState(ExecutionState.SystemRequired);
                }
            }
            else
                info.ProgressState = TaskbarItemProgressState.Error;

        }

        #endregion

        #region Class Methods

        private static int CountFiles(IEnumerable<DownloadModule> queuedDownloads, Func<DownloadFile, bool> predicate)
        {
            return queuedDownloads.SelectMany(dm => dm.Context.Files).Where(predicate).Count();
        }

        private static bool HasFailedDownload(IEnumerable<DownloadModule> queuedDownloads)
        {
            return queuedDownloads.Any(dm => dm.Context.Files.Any(df => df.DownloadState == TaskProgressState.Failed));
        }

        #endregion

        [FlagsAttribute]
        private enum ExecutionState : uint
        {
            SystemRequired = 0x00000001,
            //DisplayRequired = 0x00000002,
            //UserPresent   = 0x00000004,
            //Continuous = 0x80000000,
        }
    }
}